<?php
/** The default autoloader
 *
 *
 */
class Yz_Autoloader
{

    /** Initialize autoloader
     *  @param string the path to libs directory, usually ./lib
     *  @return int 0 on success
     */
    public static function init($libDir)
    {
        static $initDone;
        if (! $initDone) {
            defined('YZ_LIB') or define('YZ_LIB', realpath($libDir) . '/');

            set_include_path( YZ_LIB );

            class_alias(get_called_class(), 'Autoloader');
            spl_autoload_register( 'Autoloader::autoload', true );
            $initDone = true;
        }
        return 0;
    }


    /**
     *  Load a class if it had not been loaded before
     *  Called from spl_autoload(), do not call directly
    *   @param string $className
    *   @return string $className
    *   @throw Yz_Exception_ClassNotFound
    */
    public static function autoload( $className )
    {
        $className = static::testClassName($className);
        $loaded = static::doLoadClass($className);
        if (false === $loaded) {
            // avoiding possible infinite recursion
            require_once( 'Yz/Exception/ClassNotFound.php' );
            throw Yz_Exception_ClassNotFound::_new(array(
                'class' => $className,
            ));
        }
        return $loaded;
    }


    /**
     *  User-API method to load a class or verify that it's loaded
    *   @param string className
    *   @return className|false
    */
    public static function loadClass( $className )
    {
        $className = static::testClassName($className);

        if ( class_exists( $className, false ) || interface_exists( $className, false ) ) {
            return $className;
        }
        return static::doLoadClass($className);
    }


    /**
     *
     *
     */
    public function __construct()
    {
        throw new Yz_Exception("Constructor forbidden");
    }


    /**
     *
     *
     */
    public static function __callStatic($method, $args)
    {
        throw new Yz_Exception("Undefined method called");
    }



    /**
     *  Load a class for the Yz system, i.e.
    *   @param string className
    *   @return className|false
    */
    protected static function doLoadClass( $className )
    {
        $fileName = YZ_LIB . strtr( $className, '_\\', '//' ) . '.php';
        if ( is_file($fileName) ) {
            include_once( $fileName );
            // finally, check if the file does contain the class
            if ( class_exists( $className, false ) || interface_exists( $className, false ) ) {
                return $className;
            }
        }
        return false;
    }

    protected static function testClassName( $className )
    {
        if ( ! is_string($className) ) {
            throw Yz_Exception_InvalidValueType::_new(array(
                'arg' => 'Class Name',
                'type' => gettype($className),
                'expect' => 'string',
            ));
        }
        return $className;
    }

}
